﻿namespace ChangeTrackingSimpleSample
{
    using ChangeTracking;
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;

    public sealed class Entity
    {
        public string Name { get; set; }

        public double Value { get; set; }
    }

    public sealed class Database
    {
        public List<Entity> Entities { get; set; }

        public Database()
        {
            Entities = new List<Entity>();
        }
    }

    internal class App : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private Database database;

        public Database Database
        {
            get
            {
                return database;
            }
            set
            {
                database = value;
                if (PropertyChanged != null)
                    PropertyChanged(this,
                            new PropertyChangedEventArgs("Database"));
            }
        }

        private ChangeTracker tracker;

        private void Sample()
        {
            Database = new Database();
            tracker = new ChangeTracker(database);

            using (Transaction transaction = tracker.StartTransaction())
            {
                Entity entity = new Entity()
                {
                    Name = "Name of entity",
                    Value = 1.0
                };
                database.Entities.Add(entity);
                transaction.Commit("Add entity");
            }

            using (Transaction transaction = tracker.StartTransaction())
            {
                Entity entity = database.Entities[0];
                entity.Value = 2.0;
                transaction.Commit("Edit entity");
            }

            using (Transaction transaction = tracker.StartTransaction())
            {
                Entity entity = database.Entities[0];
                database.Entities.Remove(entity);
                transaction.Commit("Remove entity");
            }

            tracker.Undo(); // remove entity
            tracker.Undo(); // edit entity
            tracker.Undo(); // add entity

            tracker.Redo(); // add entity
            tracker.Redo(); // edit entity
            tracker.Redo(); // remove entity

            Transaction inspectedTransaction = tracker.StartTransaction();
            Entity changedEntity = database.Entities[0];
            changedEntity.Value = 3.0;
            inspectedTransaction.Commit("A change for tracking");
            Digraph.Arc<object, Property> newRelation =
                inspectedTransaction.ObjectGraphDifference.AddedArcs[0];
            Entity childEntity = newRelation.FromVertex.Content as Entity;
            double newValue = (double)newRelation.ToVertex.Content;
            Database parentDb = newRelation.FromVertex
                                           .IncomingArcs[0]
                                           .FromVertex
                                           .Content as Database;
            Digraph.Arc<object, Property> oldRelation =
                inspectedTransaction.ObjectGraphDifference.RemovedArcs[0];
            double oldValue = (double)oldRelation.ToVertex.Content;

            try
            {
                using (Transaction transaction = tracker.StartTransaction())
                {
                    Entity entity = new Entity()
                    {
                        Name = "Name of entity",
                        Value = 1.0
                    };
                    database.Entities.Add(entity);
                    throw new Exception("Some exception in code.");
                    transaction.Commit("Unreachable code");
                }
                // Transaction is rolled back.
            }
            catch (Exception)
            {
            }
            // Entities are empty because of last transaction rollback.

            // Bump changes for binding.
            if (PropertyChanged != null)
                PropertyChanged(this,
                        new PropertyChangedEventArgs("Database"));
        }
    }
}